package com.pingan.aspect;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.pingan.annotation.RequiredLog;
import com.pingan.mapper.LogMapper;
import com.pingan.pojo.SysLog;
import com.pingan.service.LogService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Component
@Aspect
@Slf4j
public class SysLogAspect {
    @Autowired
    private LogService logService;

    @Pointcut("@annotation(com.pingan.annotation.RequiredLog)")
    public void doLog(){}

    @Around("doLog()")
    public Object doAround(ProceedingJoinPoint point) throws Throwable{
        long t1 = System.currentTimeMillis();
        try {
            Object result = point.proceed();
            long t2 = System.currentTimeMillis();
            doLogInfo(point,t2-t1,null);
            return result;
        } catch (Throwable e) {
            e.printStackTrace();
            long t2 = System.currentTimeMillis();
            doLogInfo(point,t2-t1,e);
            throw e;
        }
    }

    private void doLogInfo(
            ProceedingJoinPoint point,Long time,Throwable e) throws Exception{
        String username = "cgb";
        String ip = "127.0.0.1";
        Class<?> aClass = point.getTarget().getClass();
        MethodSignature ms = (MethodSignature)point.getSignature();
        Method method = aClass.getMethod(ms.getName(), ms.getParameterTypes());
        //1.3.3 获取方法上 RequiredLog 注解
        RequiredLog annotation =
                method.getAnnotation(RequiredLog.class);
        //1.3.4 获取注解中定义操作名
        String operation=annotation.operation();
        //1.4 获取方法声明(类全名+方法名)
        String classMethodName=
                aClass.getName()+"."+method.getName();
        //1.5 获取方法实际参数信息
        Object[]args=point.getArgs();
        String params=new ObjectMapper().writeValueAsString(args);
        //2.封装用户行为日志
        SysLog sysLog=new SysLog();
        sysLog.setUsername(username);
        sysLog.setIp(ip);
        sysLog.setOperation(operation);
        sysLog.setMethod(classMethodName);
        sysLog.setParams(params);
        sysLog.setTime(time);
        if(e!=null) {
            sysLog.setStatus(0);
            sysLog.setError(e.getMessage());
        }
        //3.打印日志
        String userLog=new ObjectMapper()
                .writeValueAsString(sysLog);
        log.info("user.oper {}",userLog);
        logService.saveLog(sysLog);
    }
}
